﻿using DotNetty.Buffers;
using QQ.Client;
using QQ.Codecs;
using QQ.Utils;
using System;
using static QQ.Codecs.DotNettyByteBufferExtensions.LengthType;

namespace QQ.Packet
{
    public class HeadPacket : Request.IRequest, Response.IResponse
    {
        public enum EncryptType : byte
        {
            NULL = 0,
            D2KEY = 1,
            ZERO = 2,
        }

        private string uin { get; set; }
        public int packetType { get; set; } = 0x0A;//or 0X0B
        public EncryptType encryptType { get; set; }
        private byte magicNum { get; set; } = 0;//always == 0???
        public IByteBuffer body { get; set; }//uni packet/sso packet
        public IByteBuffer extraData { get; set; }
        public int sequenceId { get; set; }

        private readonly LoginSigInfo loginSigInfo;

        public HeadPacket(LoginSigInfo loginSigInfo)
        {
            this.loginSigInfo = loginSigInfo;
        }

        public void Deserialize(IByteBuffer buffer)
        {
            packetType = buffer.ReadInt();
            encryptType = (EncryptType)buffer.ReadByte();
            magicNum = buffer.ReadByte();
            uin = buffer.ReadBytesWithLength(INT, -4).GetString();
            body = buffer.ReadRemaining();
            body = (encryptType switch
            {
                EncryptType.ZERO => QQTea.Decrypt(body.ToArray(), new byte[16]),
                EncryptType.D2KEY => QQTea.Decrypt(body.ToArray(), loginSigInfo.d2Key.ToArray()),
                EncryptType.NULL => body.ToArray(),
                _ => throw new ArgumentException($"解析{nameof(encryptType)}错误")
            }).ToByteBuffer();
        }

        public IByteBuffer Serialize()
        {
            IByteBuffer ret = Unpooled.Buffer().WriteInt(packetType).WriteByte((byte)encryptType);
            if (packetType == 0x0A) ret.WriteBytesWithLength(extraData == null ? Unpooled.Buffer() : extraData, INT, lengthOffset: 4);
            else if (packetType == 0x0B) ret.WriteInt(sequenceId);
            else throw new ArgumentException($"{nameof(packetType)} 错误了。");
            ret.WriteByte(magicNum).WriteBytesWithLength(loginSigInfo.uin.ToString().ToByteBuffer(), INT, lengthOffset: 4);
            _ = (encryptType switch
            {
                EncryptType.ZERO => ret.WriteBytes(QQTea.Encrypt(body.ToArray(), new byte[16])),
                EncryptType.D2KEY => ret.WriteBytes(QQTea.Encrypt(body.ToArray(), loginSigInfo.d2Key.ToArray())),
                EncryptType.NULL => ret.WriteBytes(body),
                _ => throw new ArgumentException($"输入{nameof(encryptType)}错误")
            });
            return ret;
        }
    }
}
